package cn.wolfcode.shiro;

import cn.wolfcode.domain.Employee;
import cn.wolfcode.service.IEmployeeService;
import cn.wolfcode.service.IPermissionService;
import cn.wolfcode.service.IRoleService;
import cn.wolfcode.util.UserContext;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * 自定义数据源
 */
@Component
public class CRMRealm extends AuthorizingRealm {

    @Autowired
    private IEmployeeService employeeService;
    @Autowired
    private IPermissionService permissionService;
    @Autowired
    private IRoleService roleService;

    //将容器中的配置的凭证匹配器注入给当前的realm对象
    @Autowired
    public void setCredentialsMatcher(CredentialsMatcher matcher){
        super.setCredentialsMatcher(matcher);
    }

    /**
     * 提供授权信息
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //1.获取当前登录的员工的对象,获取员工id
        Employee currentUser = UserContext.getCurrentUser();
        Long empId = currentUser.getId();
        //Employee employee = (Employee) principals.getPrimaryPrincipal();

        //创建对象
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //2.查询数据库中该员工的拥有的角色和权限的数据
        if (!currentUser.isAdmin()){
            List<String> expressions = permissionService.selectPermissionByEmpId(empId);
            List<String> roles = roleService.selectRoleByEmpId(empId);
            info.addStringPermissions(expressions);
            //3.设置当前登录用户拥有的权限和角色
            info.addRoles(roles);
            //System.out.println(info.getRoles() + "---------------");
            //System.out.println(info.getStringPermissions() + "---------------");
        }else {
            //权限拦截的功能shiro来做的,不知道employee的属性意义
            //还是按照权限表达式来判断的,可以给通配符
            info.addStringPermission("*:*");
            info.addRole("admin");
            //System.out.println(info.getRoles() + "---------------");
        }
        return info;
    }

    /**
     * 提供认证信息
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //当前的方法如果直接返回null,shiro会自动抛出账号不存在的异常
        //如果直接返回不为null,shiro会自动从返回的对象获取真实的密码,去和token对比

        //1.获取令牌中的用户名(前端传来的)
        String username = (String) token.getPrincipal();
        //2.查询数据库中是否存在该员工()
        Employee employee = employeeService.selectByName(username);
        //3.如果不存在,直接返回null
        if (employee != null){
            //如果直接抛shiro提供的异常就不会被封装,抛自定义的异常就会被shiro封装
            if (!employee.isStatus()){
                throw new DisabledAccountException("账号被禁用");
            }
            //4.如果存在,返回SimpleAuthenticationInfo对象
            //身份信息可以在任意地方获取,用来根subject绑定在一起
            //在项目中时就直接传入员工对象,根subject绑定在一起,方便后续在任意地方获取当前登录用户信息
            //传入真实密码,shiro会自动判断是否正确
            //传入当前数据源的名字,对于我们现在的项目没有作用
            //一般是一个项目中有多个数据源时,需要做标志,代表数据是从哪个数据源查的

            //返回加盐加密的 密码
            return new SimpleAuthenticationInfo(employee,employee.getPassword(),
                    ByteSource.Util.bytes(username),this.getName());
        }
        return null;
    }
}
